package web

import (
	"errors"
	"forum/internal/application"
	"forum/internal/common"
	"forum/internal/common/slice"
	"forum/internal/domain"
	"forum/internal/domain/vo"
	application2 "forum/intr/application"
	domain2 "forum/intr/domain"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
)

type ArticleHandler struct {
	articleSvc application.ArticleService
	interSvc   application2.InteractiveService
	biz        string
}

func NewArticleHandler(articleSvc application.ArticleService, interSvc application2.InteractiveService) *ArticleHandler {
	return &ArticleHandler{
		articleSvc: articleSvc,
		interSvc:   interSvc,
		biz:        "article",
	}
}

func (a *ArticleHandler) RegisterRouter(server *gin.Engine) {
	articleRouter := server.Group("/article")
	articleRouter.POST("/edit", a.Edit)
	articleRouter.POST("/publish", a.Publish)
	articleRouter.GET("/list", a.List)
	articleRouter.GET("/:id", a.Detail)
	pubArticleRouter := articleRouter.Group("/pub")
	pubArticleRouter.GET("/:id", a.PubDetail)
	pubArticleRouter.POST("/like/:id", a.Like)
	pubArticleRouter.POST("/collect/:id", a.Collect)
}

// Edit TODO TEST
func (a *ArticleHandler) Edit(ctx *gin.Context) {
	type Req struct {
		Id      int64  `json:"id"`
		Title   string `json:"title"`
		Content string `json:"content"`
	}
	var req Req
	err := ctx.Bind(&req)
	if err != nil {
		return
	}
	uc := ctx.MustGet("claim").(application.UserClaim)
	id, err := a.articleSvc.Edit(ctx, uc.Id, domain.Article{
		Id:      req.Id,
		Title:   req.Title,
		Content: req.Content,
		Author: domain.Author{
			Id: uc.Id,
		},
	})
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    20001,
			Message: "保存失败",
			Data:    nil,
		})
		return
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    20000,
		Message: "保存成功",
		Data:    id,
	})
}

func (a *ArticleHandler) Publish(ctx *gin.Context) {
	type Req struct {
		Id      int64  `json:"id"`
		Title   string `json:"title"`
		Content string `json:"content"`
	}
	var req Req
	err := ctx.Bind(&req)
	if err != nil {
		return
	}
	claim := ctx.MustGet("claim").(application.UserClaim)
	id, err := a.articleSvc.Publish(ctx, claim.Id, domain.Article{
		Id:      req.Id,
		Title:   req.Title,
		Content: req.Content,
		Author: domain.Author{
			Id: claim.Id,
		},
	})
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    22002,
			Message: "发布失败",
			Data:    nil,
		})
		return
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    22000,
		Message: "发表成功",
		Data:    id,
	})
}

func (a *ArticleHandler) List(ctx *gin.Context) {
	var cursor vo.Page

	claim := ctx.MustGet("claim").(application.UserClaim)
	// 获取查询参数 offset 和 limit，并转换为整数
	var err error
	offsetStr := ctx.Query("offset")
	cursor.Offset, err = strconv.Atoi(offsetStr)
	if err != nil {
		// 处理转换错误
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid offset"})
		return
	}

	limitStr := ctx.Query("limit")
	cursor.Limit, err = strconv.Atoi(limitStr)
	if err != nil {
		// 处理转换错误
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit"})
		return
	}

	list, err := a.articleSvc.GetList(ctx, claim.Id, cursor)
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    23001,
			Message: "获取失败",
			Data:    nil,
		})
		return
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    23000,
		Message: "获取成功",
		Data: slice.Map[domain.Article, vo.ArticleVo](list, func(idx int, src domain.Article) vo.ArticleVo {
			return vo.ArticleVo{
				Id:       src.Id,
				Title:    src.Title,
				Abstract: src.Abstract(),
				AuthorId: src.Author.Id,

				Status: src.Status.ToUnit8(),
				Ctime:  src.Ctime,
				Utime:  src.Utime,
			}
		}),
	})
	return
}

func (a *ArticleHandler) Detail(ctx *gin.Context) {
	idStr := ctx.Param("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		// 处理转换错误
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Id"})
		return
	}
	user := ctx.MustGet("claim").(application.UserClaim)
	art, err := a.articleSvc.AuthorGetDetail(ctx, id, user.Id)
	if errors.Is(err, common.ErrNotAuthor) {
		ctx.JSON(http.StatusOK, Response{
			Code:    24001,
			Message: "系统错误",
			Data:    nil,
		})
		return
	}
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    24002,
			Message: "系统错误",
			Data:    nil,
		})
		return
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    24000,
		Message: "获取成功",
		Data:    art,
	})
	return
}

func (a *ArticleHandler) PubDetail(ctx *gin.Context) {
	idStr := ctx.Param("id")
	user := ctx.MustGet("claim").(application.UserClaim)
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Id"})
		return
	}
	//获取文章
	art, err := a.articleSvc.GetPubDetail(ctx, id, user.Id)
	if err != nil {
		ctx.JSON(http.StatusOK, Response{
			Code:    25001,
			Message: "系统错误",
			Data:    nil,
		})
		return
	}
	//获取阅读 点赞 收藏
	InterChan := make(chan domain2.Interactive)
	go func() {
		Into, iErr := a.interSvc.Get(ctx, a.biz, id, user.Id)
		if iErr != nil {
			//log
			InterChan <- domain2.Interactive{}
			return
		}
		InterChan <- Into
	}()
	//// 增加阅读计数
	//go func() {
	//	iErr := a.interSvc.IncrReadCnt(ctx, a.biz, id)
	//	if iErr != nil {
	//		//log
	//		return
	//	}
	//}()

	Inter := <-InterChan
	ctx.JSON(http.StatusOK, Response{
		Code:    25000,
		Message: "获取成功",
		Data: vo.ArticleVo{
			Id:    art.Id,
			Title: art.Title,

			Content:    art.Content,
			AuthorId:   art.Author.Id,
			AuthorName: art.Author.Name,

			ReadCnt:    Inter.ReadCnt,
			LikeCnt:    Inter.LikeCnt,
			CollectCnt: Inter.CollectCnt,

			Liked:     Inter.Liked,
			Collected: Inter.Collected,

			Status: art.Status.ToUnit8(),
			Ctime:  art.Ctime,
			Utime:  art.Utime,
		},
	})
	return
}

func (a *ArticleHandler) Like(ctx *gin.Context) {
	idStr := ctx.Param("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Id"})
		return
	}
	type Req struct {
		Liked bool `json:"liked"`
	}
	var req Req
	err = ctx.Bind(&req)
	if err != nil {
		return
	}
	user := ctx.MustGet("claim").(application.UserClaim)
	if req.Liked {
		err := a.interSvc.Like(ctx, a.biz, id, user.Id)
		if err != nil {
			ctx.JSON(http.StatusOK, Response{
				Code:    31001,
				Message: "点赞失败",
				Data:    nil,
			})
			return
		}
	} else {
		err := a.interSvc.CancelLike(ctx, a.biz, id, user.Id)
		if err != nil {
			ctx.JSON(http.StatusOK, Response{
				Code:    31002,
				Message: "取消点赞失败",
				Data:    nil,
			})
			return
		}
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    31000,
		Message: "操作成功",
		Data:    nil,
	})
}

func (a *ArticleHandler) Collect(ctx *gin.Context) {
	idStr := ctx.Param("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"": ""})
	}
	user := ctx.MustGet("claim").(application.UserClaim)
	type Req struct {
		Collected bool `json:"collected"`
	}
	var req Req
	err = ctx.Bind(&req)
	if err != nil {
		return
	}
	if req.Collected {
		err := a.interSvc.Collect(ctx, a.biz, id, user.Id)
		if err != nil {
			ctx.JSON(http.StatusOK, Response{
				Code:    32001,
				Message: "收藏失败",
				Data:    nil,
			})
			return
		}
	} else {
		err := a.interSvc.CancelCollect(ctx, a.biz, id, user.Id)
		if err != nil {
			ctx.JSON(http.StatusOK, Response{
				Code:    32002,
				Message: "取消收藏失败",
				Data:    nil,
			})
			return
		}
	}
	ctx.JSON(http.StatusOK, Response{
		Code:    32000,
		Message: "操作成功",
		Data:    nil,
	})
}
